home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 3: Developer Tools / Linux Cubed Series 3 - Developer Tools.iso / utils / file / managers / git-4.3 / git-4 / git-4.3.7 / src / tty.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-07-10  |  42.7 KB  |  1,639 lines

  1. /* tty.c -- the tty management file. This includes termcap / terminfo
  2.    initialization, colors, keys and functions to switch terminals
  3.    between canonical and noncanonical modes.  */
  4.  
  5. /* Copyright (C) 1993, 1994, 1995 Free Software Foundation, Inc.
  6.  
  7.    This program is free software; you can redistribute it and/or modify
  8.    it under the terms of the GNU General Public License as published by
  9.    the Free Software Foundation; either version 2, or (at your option)
  10.    any later version.
  11.  
  12.    This program is distributed in the hope that it will be useful,
  13.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.    GNU General Public License for more details.
  16.  
  17.    You should have received a copy of the GNU General Public License
  18.    along with this program; if not, write to the Free Software
  19.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /* Written by Tudor Hulubei and Andrei Pitis.  */
  22.  
  23.  
  24. #ifdef HAVE_CONFIG_H
  25. #include <config.h>
  26. #endif
  27.  
  28. #include <stdio.h>
  29.  
  30. #ifdef HAVE_STDLIB_H
  31. #include <stdlib.h>
  32. #else /* !HAVE_STDLIB_H */
  33. #include "ansi_stdlib.h"
  34. #endif /* !HAVE_STDLIB_H */
  35.  
  36. #include <sys/types.h>
  37. #include <ctype.h>
  38. #include "file.h"
  39. #include <fcntl.h>
  40. #include <sys/ioctl.h>
  41.  
  42. #ifdef HAVE_UNISTD_H
  43. #include <unistd.h>
  44. #endif /* HAVE_UNISTD_H */
  45.  
  46. #include "stdc.h"
  47. #include "xstring.h"
  48. #include "xmalloc.h"
  49. #include "xtimer.h"
  50. #include "xio.h"
  51. #include "tty.h"
  52. #include "misc.h"
  53.  
  54.  
  55. /* We want to avoid including curses.h or any other header file that defines
  56.    these. It's safer because I couldn't find 2 similar curses.h files in the
  57.    entire world...  */
  58.  
  59. int tgetent __P((void *__buffer, const char *__termtype));
  60. int tputs __P((const char *__string, int __nlines, int (*outfun)()));
  61. char *tgetstr __P((const char *__name, char **__area));
  62. char *tgoto __P((const char *__cstring, int __hpos, int __vpos));
  63.  
  64.  
  65. #define TTY_INPUT       0
  66. #define TTY_OUTPUT      1
  67.  
  68.  
  69. /* If tty_kbdmode == 1, single characters are inserted in the linked list.
  70.    This feature is used by gitps (it has no command line).  */
  71. static int tty_kbdmode = 0; 
  72.  
  73. #ifdef HAVE_POSIXTTY
  74. static struct termios old_term;
  75. static struct termios new_term;
  76. #else
  77. #ifdef HAVE_SYSTEMVTTY
  78. static struct termio old_term;
  79. static struct termio new_term;
  80. #else
  81. static struct sgttyb  old_arg;
  82. static struct tchars  old_targ;
  83. static struct ltchars old_ltarg;
  84. static struct sgttyb  new_arg;
  85. static struct tchars  new_targ;
  86. static struct ltchars new_ltarg;
  87.  
  88. /* NextStep doesn't define TILDE.  */
  89. #ifndef TILDE
  90. #define TILDE 0
  91. #endif
  92.  
  93. #endif /* HAVE_SYSTEMVTTY */
  94. #endif /* HAVE_POSIXTTY */
  95.  
  96.  
  97. #ifdef HAVE_LINUX
  98. static int vcs_read_ok;
  99. #endif /* HAVE_LINUX */
  100.  
  101. static int tty_cursor_x;
  102. static int tty_cursor_y;
  103. static int rows, columns;
  104. static int tty_cursormove_notified;
  105. static int fg_color, bg_color, br_status, rv_status, cursor_status;
  106.  
  107. static unsigned char tty_current_attribute;
  108.  
  109. /* tty_screen will always contain a copy of the screen, while tty_attributes
  110.    will be used to keep track of screen attributes.  */
  111. static unsigned char *tty_screen     = NULL;
  112. static unsigned char *tty_attributes = NULL;
  113.  
  114.  
  115. /* The ANSI color sequences are hard coded here because I figured out that
  116.    the Linux console, the Linux color_xterm and the Ultrix xterm use them.
  117.    If you find a terminal (or terminal emulator) that use different  color
  118.    sequences, please mail me (tudor@chang.pub.ro) and I'll try to fix this
  119.    Meanwhile, you're out of luck...  */ 
  120. static char ansi_foreground[] = { 0x1b, '[', '3', '0', 'm' };
  121. static char ansi_background[] = { 0x1b, '[', '4', '0', 'm' };
  122.  
  123. #ifdef HAVE_LINUX
  124. /* Linux also has these...  */
  125. static char lc_attr_off[] = { 0x1b, '[', 'm' };
  126. static char lc_defaults[] = { 0x1b, '[', '0', 'm' };
  127. #endif /* HAVE_LINUX */
  128.  
  129.  
  130. /* These variable tells us if we should use standard ANSI color sequences.
  131.    Its value is taken from the configuration file.  */
  132. extern int AnsiColorSequences;
  133.  
  134.  
  135. #ifdef HAVE_LINUX
  136. /* These variable tells us if we are using a Linux console.  */
  137. int LinuxConsole;
  138. #endif /* HAVE_LINUX */
  139.  
  140.  
  141. /* Structures for keys management.  */
  142. tty_key_t *key_list_head = NULL;
  143. tty_key_t *current_key;
  144. tty_key_t default_key;
  145.  
  146. static char tty_buf[MAX_CAPABILITY_LEN];
  147. static unsigned int tty_index = 0;
  148.  
  149. static char term_buf[2048];
  150. static char vt100[] = "vt100";
  151.  
  152. /* The terminal mode. TTY_CANONIC at the begining.  */
  153. int tty_mode = TTY_CANONIC;
  154.  
  155. /* The curses-like optimization level.  See the tty_write() comment.  */
  156. int tty_optimization_level = 0;
  157.  
  158. char *tty_type;
  159.  
  160. char PC;        /* for tputs */
  161. char *BC;       /* for tgoto */
  162. char *UP;
  163.  
  164. #ifdef HAVE_LINUX
  165. speed_t ospeed;
  166. #else   /* !HAVE_LINUX */
  167. short ospeed;
  168. #endif  /* !HAVE_LINUX */
  169.  
  170.  
  171. /* A structure describing some attributes we need to know about each
  172.    capability. See below for greater detail.  */
  173. typedef struct
  174. {
  175.     char *capability;
  176.     char *name;
  177.     int  indispensable;
  178.     char *symbol;
  179. } TTY_CAPABILITY;
  180.  
  181.  
  182. #define TTY_USED_CAPABILITIES   31
  183. #define TTY_FIRST_SYMBOL_KEY    10
  184.  
  185. static TTY_CAPABILITY tty_capability[TTY_USED_CAPABILITIES] =
  186. {
  187.     { NULL, "me", 0, NULL },            /* turn off all attributes */
  188.     { NULL, "mr", 0, NULL },            /* turn on reverse video mode */
  189.     { NULL, "md", 0, NULL },            /* turn on bold */
  190.     { NULL, "vi", 0, NULL },            /* make the cursor invisible */
  191.     { NULL, "ve", 0, NULL },            /* make the cursor appear normal */
  192.     { NULL, "cl", 1, NULL },            /* clear screen and home the cursor */
  193.     { NULL, "cm", 1, NULL },            /* move the cursor */
  194.     { NULL, "pc", 0, NULL },            /* padding character */
  195.     { NULL, "up", 0, NULL },            /* up one line */
  196.     { NULL, "le", 0, NULL },            /* move left one space */
  197.     { NULL, "ku", 0, "UP" },            /* (UP) */
  198.     { NULL, "kd", 0, "DOWN" },          /* (DOWN) */
  199.     { NULL, "kr", 0, "RIGHT" },         /* (RIGHT) */
  200.     { NULL, "kl", 0, "LEFT" },          /* (LEFT) */
  201.     { NULL, "kI", 0, "INS" },           /* (INS) */
  202.     { NULL, "kD", 0, "DEL" },           /* (DEL) */
  203.     { NULL, "kh", 0, "HOME" },          /* (HOME) */
  204.     { NULL, "kH", 0, "END" },           /* (END) */
  205.     { NULL, "kP", 0, "PGUP" },          /* (PGUP) */
  206.     { NULL, "kN", 0, "PGDOWN" },        /* (PGDOWN) */
  207.     { NULL, "k0", 0, "F0" },            /* (F0) */
  208.     { NULL, "k1", 0, "F1" },            /* (F1) */
  209.     { NULL, "k2", 0, "F2" },            /* (F2) */
  210.     { NULL, "k3", 0, "F3" },            /* (F3) */
  211.     { NULL, "k4", 0, "F4" },            /* (F4) */
  212.     { NULL, "k5", 0, "F5" },            /* (F5) */
  213.     { NULL, "k6", 0, "F6" },            /* (F6) */
  214.     { NULL, "k7", 0, "F7" },            /* (F7) */
  215.     { NULL, "k8", 0, "F8" },            /* (F8) */
  216.     { NULL, "k9", 0, "F9" },            /* (F9) */
  217.     { NULL, "k;", 0, "F10" },           /* (F10) */
  218. };
  219.  
  220.  
  221. /* Some nice aliases...  */
  222. #define TTY_ATTRIBUTES_OFF      (tty_capability[0].capability)
  223. #define TTY_REVERSE_ON          (tty_capability[1].capability)
  224. #define TTY_BRIGHT_ON           (tty_capability[2].capability)
  225. #define TTY_CURSOR_OFF          (tty_capability[3].capability)
  226. #define TTY_CURSOR_ON           (tty_capability[4].capability)
  227. #define TTY_CLEAR_SCREEN        (tty_capability[5].capability)
  228. #define TTY_CURSOR_MOVE         (tty_capability[6].capability)
  229. #define TTY_PAD_CHAR            (tty_capability[7].capability)
  230. #define TTY_UP_ONE_LINE         (tty_capability[8].capability)
  231. #define TTY_LEFT_ONE_SPACE      (tty_capability[9].capability)
  232.  
  233.  
  234. /* Some more nice aliases.  */
  235. #define TTY_ATTRIBUTES_OFF_NAME (tty_capability[0].name)
  236. #define TTY_REVERSE_ON_NAME     (tty_capability[1].name)
  237. #define TTY_BRIGHT_ON_NAME      (tty_capability[2].name)
  238. #define TTY_CURSOR_OFF_NAME     (tty_capability[3].name)
  239. #define TTY_CURSOR_ON_NAME      (tty_capability[4].name)
  240. #define TTY_CLEAR_SCREEN_NAME   (tty_capability[5].name)
  241. #define TTY_CURSOR_MOVE_NAME    (tty_capability[6].name)
  242. #define TTY_PAD_CHAR_NAME       (tty_capability[7].name)
  243. #define TTY_UP_ONE_LINE_NAME    (tty_capability[8].name)
  244. #define TTY_LEFT_ONE_SPACE_NAME (tty_capability[9].name)
  245.  
  246.  
  247. #ifdef HAVE_LIBTERMCAP
  248.  
  249. static char term_database[] = "termcap";
  250. static char term_env[]      = "TERMCAP";
  251.  
  252. #else   /* !HAVE_LIBTERMCAP */
  253.  
  254. static char term_database[] = "terminfo";
  255. static char term_env[]      = "TERMINFO";
  256.  
  257. #endif  /* !HAVE_LIBTERMCAP */
  258.  
  259.  
  260. void fatal __P((char *));
  261.  
  262.  
  263. /* ANSI colors. OFF & ON are here because we need them when we read the
  264.    configuration file. Don't bother...  */
  265. static char *colors[10] = 
  266. {
  267.     "BLACK",
  268.     "RED",
  269.     "GREEN",
  270.     "YELLOW",
  271.     "BLUE",
  272.     "MAGENTA",
  273.     "CYAN",
  274.     "WHITE",
  275.     "OFF",
  276.     "ON"
  277. };
  278.  
  279.  
  280. /* I don't know any method to find out the current terminal colors. This  is
  281.    why we need to specify the colors to be restored at exit. We can't always
  282.    use a white/black default because the xterm terminal emulator use reverse
  283.    video as a default (black/white).  */
  284. static int ForegroundAtExit;    /* foreground to be restored at exit.  */
  285. static int BackgroundAtExit;    /* background to be restored at exit.  */
  286.  
  287.  
  288. /* Control keys description. C-a, C-b, C-c and so on...  */
  289. unsigned char key_ctrl_table[0x5f] = 
  290. {
  291.     0x20,                       /* 0x20 ( ) */
  292.     0x21,                       /* 0x21 (!) */
  293.     0x22,                       /* 0x22 (") */
  294.     0x23,                       /* 0x23 (#) */
  295.     0xff,                       /* 0x24 ($) */
  296.     0x25,                       /* 0x25 (%) */
  297.     0x26,                       /* 0x26 (&) */
  298.     0x07,                       /* 0x27 (') */
  299.     0x28,                       /* 0x28 (() */
  300.     0x29,                       /* 0x29 ()) */
  301.     0x2a,                       /* 0x2a (*) */
  302.     0x2b,                       /* 0x2b (+) */
  303.     0x2c,                       /* 0x2c (,) */
  304.     0x2d,                       /* 0x2d (-) */
  305.     0x2e,                       /* 0x2e (.) */
  306.     0x2f,                       /* 0x2f (/) */
  307.     0x20,                       /* 0x30 (0) */
  308.     0x20,                       /* 0x31 (1) */
  309.     0xff,                       /* 0x32 (2) */
  310.     0x1b,                       /* 0x33 (3) */
  311.     0x1c,                       /* 0x34 (4) */
  312.     0x1d,                       /* 0x35 (5) */
  313.     0x1e,                       /* 0x36 (6) */
  314.     0x1f,                       /* 0x37 (7) */
  315.     0x7f,                       /* 0x38 (8) */
  316.     0x39,                       /* 0x39 (9) */
  317.     0x3a,                       /* 0x3a (:) */
  318.     0x3b,                       /* 0x3b (;) */
  319.     0x3c,                       /* 0x3c (<) */
  320.     0x20,                       /* 0x3d (=) */
  321.     0x3e,                       /* 0x3e (>) */
  322.     0x20,                       /* 0x3f (?) */
  323.     0x20,                       /* 0x40 (@) */
  324.     0x01,                       /* 0x41 (A) */
  325.     0x02,                       /* 0x42 (B) */
  326.     0x03,                       /* 0x43 (C) */
  327.     0x04,                       /* 0x44 (D) */
  328.     0x05,                       /* 0x45 (E) */
  329.     0x06,                       /* 0x46 (F) */
  330.     0x07,                       /* 0x47 (G) */
  331.     0x08,                       /* 0x48 (H) */
  332.     0x09,                       /* 0x49 (I) */
  333.     0x0a,                       /* 0x4a (J) */
  334.     0x0b,                       /* 0x4b (K) */
  335.     0x0c,                       /* 0x4c (L) */
  336.     0x0d,                       /* 0x4d (M) */
  337.     0x0e,                       /* 0x4e (N) */
  338.     0x0f,                       /* 0x4f (O) */
  339.     0x10,                       /* 0x50 (P) */
  340.     0x11,                       /* 0x51 (Q) */
  341.     0x12,                       /* 0x52 (R) */
  342.     0x13,                       /* 0x53 (S) */
  343.     0x14,                       /* 0x54 (T) */
  344.     0x15,                       /* 0x55 (U) */
  345.     0x16,                       /* 0x56 (V) */
  346.     0x17,                       /* 0x57 (W) */
  347.     0x18,                       /* 0x58 (X) */
  348.     0x19,                       /* 0x59 (Y) */
  349.     0x1a,                       /* 0x5a (Z) */
  350.     0x1b,                       /* 0x5b ([) */
  351.     0x1c,                       /* 0x5c (\) */
  352.     0x1d,                       /* 0x5d (]) */
  353.     0x5e,                       /* 0x5e (^) */
  354.     0x7f,                       /* 0x5f (_) */
  355.     0x20,                       /* 0x60 (`) */
  356.     0x01,                       /* 0x61 (a) */
  357.     0x02,                       /* 0x62 (b) */
  358.     0x03,                       /* 0x63 (c) */
  359.     0x04,                       /* 0x64 (d) */
  360.     0x05,                       /* 0x65 (e) */
  361.     0x06,                       /* 0x66 (f) */
  362.     0x07,                       /* 0x67 (g) */
  363.     0x08,                       /* 0x68 (h) */
  364.     0x09,                       /* 0x69 (i) */
  365.     0x0a,                       /* 0x6a (j) */
  366.     0x0b,                       /* 0x6b (k) */
  367.     0x0c,                       /* 0x6c (l) */
  368.     0x0d,                       /* 0x6d (m) */
  369.     0x0e,                       /* 0x6e (n) */
  370.     0x0f,                       /* 0x6f (o) */
  371.     0x10,                       /* 0x70 (p) */
  372.     0x11,                       /* 0x71 (q) */
  373.     0x12,                       /* 0x72 (r) */
  374.     0x13,                       /* 0x73 (s) */
  375.     0x14,                       /* 0x74 (t) */
  376.     0x15,                       /* 0x75 (u) */
  377.     0x16,                       /* 0x76 (v) */
  378.     0x17,                       /* 0x77 (w) */
  379.     0x18,                       /* 0x78 (x) */
  380.     0x19,                       /* 0x79 (y) */
  381.     0x1a,                       /* 0x7a (z) */
  382.     0x20,                       /* 0x7b ({) */
  383.     0x20,                       /* 0x7c (|) */
  384.     0x20,                       /* 0x7d (}) */
  385.     0x20,                       /* 0x7e (~) */
  386. };
  387.  
  388.  
  389. #define NO      0
  390. #define YES     1
  391.  
  392. #define MAX_KEY_LENGTH    15
  393.  
  394.  
  395. #define LINUX_VC_MAJOR  4
  396.  
  397. static int  keyno    = 0;
  398. static int  keyindex = 0;
  399. static char keybuf[1024];
  400.  
  401.  
  402. /* Hooks that get called when we are going idle and when we stop
  403.    being idle.  */
  404. void (* tty_enter_idle_hook)() = NULL;
  405. void (* tty_exit_idle_hook)()  = NULL;
  406.  
  407.  
  408. void
  409. tty_startup()
  410. {
  411.     /* Fail if stdin or stdout are not real terminals.  */
  412.     if (!isatty(TTY_INPUT) || !isatty(TTY_OUTPUT))
  413.         fatal("only standard error can be redirected");
  414.  
  415.     /* Get calloc-ed memory for tty_screen & tty_attributes.  */
  416.     tty_screen     = (unsigned char *)xcalloc(columns * rows,
  417.                                               sizeof(unsigned char));
  418.     tty_attributes = (unsigned char *)xcalloc(columns * rows,
  419.                                               sizeof(unsigned char));
  420.  
  421.     tty_current_attribute = 0;
  422.  
  423.     /* Store the terminal settings in old_term. it will be used to restore
  424.        them later.  */
  425. #ifdef HAVE_POSIXTTY
  426.     tcgetattr(TTY_OUTPUT, &old_term);
  427. #else
  428. #ifdef HAVE_SYSTEMVTTY
  429.     ioctl(TTY_OUTPUT, TCGETA, &old_term);
  430. #else
  431.     ioctl(TTY_OUTPUT, TIOCGETP, &old_arg);
  432.     ioctl(TTY_OUTPUT, TIOCGETC, &old_targ);
  433.     ioctl(TTY_OUTPUT, TIOCGLTC, &old_ltarg);
  434. #endif /* HAVE_SYSTEMVTTY */
  435. #endif /* HAVE_POSIXTTY */
  436. }
  437.  
  438.  
  439. /* Initialize some keybord stuff.  */
  440.  
  441. void
  442. tty_kbdinit(kbd_mode)
  443.     int kbd_mode;
  444. {
  445.     default_key.key_seq  = (unsigned char *)xmalloc(16);
  446.     default_key.aux_data = NULL;
  447.     default_key.next     = NULL;
  448.     tty_kbdmode          = kbd_mode;
  449. }
  450.  
  451.  
  452. /* This function is used to switch between canonical and noncanonical
  453.    terminal modes.  */
  454.  
  455. void
  456. tty_set_mode(mode)
  457.     int mode;
  458. {
  459.     if (mode == TTY_NONCANONIC)
  460.     {
  461. #ifdef HAVE_POSIXTTY
  462.         new_term = old_term;
  463.         new_term.c_iflag &= ~(ICRNL | IGNCR | INLCR | IGNBRK | BRKINT);
  464.         new_term.c_oflag &= ~OPOST;
  465.         new_term.c_lflag |= ISIG | NOFLSH;
  466.         new_term.c_lflag &= ~(ICANON | ECHO);
  467.  
  468.         /* I think we will always have these:  */
  469.  
  470.         new_term.c_cc[VINTR] = key_INTERRUPT;           /* Ctrl-G */
  471.         new_term.c_cc[VQUIT] = key_INTERRUPT;           /* Ctrl-G */
  472.         new_term.c_cc[VSTART] = _POSIX_VDISABLE;        /* START (^Q) */
  473.         new_term.c_cc[VSTOP]  = _POSIX_VDISABLE;        /* STOP (^S) */
  474.         new_term.c_cc[VMIN]  = 1;
  475.         new_term.c_cc[VTIME] = 0;
  476.  
  477.         /* ... but not always these:  (in fact I am not sure if I really
  478.            need to overwrite all these, but just in case... */
  479.  
  480. #ifdef VERASE
  481.         new_term.c_cc[VERASE] = _POSIX_VDISABLE;
  482. #endif
  483.  
  484. #ifdef VKILL
  485.         new_term.c_cc[VKILL] = _POSIX_VDISABLE;
  486. #endif
  487.  
  488. #ifdef VEOL
  489.         new_term.c_cc[VEOL] = _POSIX_VDISABLE;
  490. #endif
  491.  
  492. #ifdef VEOL2
  493.         new_term.c_cc[VEOL2] = _POSIX_VDISABLE;
  494. #endif
  495.  
  496. #ifdef VSWTCH
  497.         new_term.c_cc[VSWTCH] = _POSIX_VDISABLE;
  498. #endif
  499.  
  500. #ifdef VSUSP
  501.         new_term.c_cc[VSUSP] = key_SUSPEND;             /* Ctrl-Z */
  502. #endif
  503.  
  504. #ifdef VDSUSP
  505.         new_term.c_cc[VDSUSP] = _POSIX_VDISABLE;
  506. #endif
  507.  
  508. #ifdef VREPRINT
  509.         new_term.c_cc[VREPRINT] = _POSIX_VDISABLE;
  510. #endif
  511.  
  512. #ifdef VDISCARD
  513.         new_term.c_cc[VDISCARD] = _POSIX_VDISABLE;
  514. #endif
  515.  
  516. #ifdef VWERASE
  517.         new_term.c_cc[VWERASE] = _POSIX_VDISABLE;
  518. #endif
  519.  
  520. #ifdef VLNEXT
  521.         new_term.c_cc[VLNEXT] = _POSIX_VDISABLE;
  522. #endif
  523.  
  524.         tcsetattr(TTY_OUTPUT, TCSADRAIN, &new_term);
  525.         ospeed = cfgetospeed(&new_term);
  526. #else
  527. #ifdef HAVE_SYSTEMVTTY
  528.         new_term = old_term;
  529.         new_term.c_iflag &= ~(ICRNL | IGNCR | INLCR);
  530.         new_term.c_oflag = 0;
  531.         new_term.c_lflag = 0;
  532.  
  533.         /* I think we will always have these:  */
  534.  
  535.         new_term.c_cc[VINTR] = key_INTERRUPT;   /* Ctrl-G */
  536.         new_term.c_cc[VQUIT] = key_INTERRUPT;   /* Ctrl-G */
  537.         new_term.c_cc[VSTART] = -1;             /* START (^Q) */
  538.         new_term.c_cc[VSTOP]  = -1;             /* STOP (^S) */
  539.         new_term.c_cc[VMIN]  = 1;
  540.         new_term.c_cc[VTIME] = 0;
  541.  
  542.         /* ... but not always these:  (in fact I am not sure if I really
  543.            need to overwrite all these, but just in case... */
  544.  
  545. #ifdef VERASE
  546.         new_term.c_cc[VERASE] = _POSIX_VDISABLE;
  547. #endif
  548.  
  549. #ifdef VKILL
  550.         new_term.c_cc[VKILL] = _POSIX_VDISABLE;
  551. #endif
  552.  
  553. #ifdef VEOL
  554.         new_term.c_cc[VEOL] = _POSIX_VDISABLE;
  555. #endif
  556.  
  557. #ifdef VEOL2
  558.         new_term.c_cc[VEOL2] = _POSIX_VDISABLE;
  559. #endif
  560.  
  561. #ifdef VSWTCH
  562.         new_term.c_cc[VSWTCH] = _POSIX_VDISABLE;
  563. #endif
  564.  
  565. #ifdef VSUSP
  566.         new_term.c_cc[VSUSP] = key_SUSPEND;             /* Ctrl-Z */
  567. #endif
  568.  
  569. #ifdef VDSUSP
  570.         new_term.c_cc[VDSUSP] = _POSIX_VDISABLE;
  571. #endif
  572.  
  573. #ifdef VREPRINT
  574.         new_term.c_cc[VREPRINT] = _POSIX_VDISABLE;
  575. #endif
  576.  
  577. #ifdef VDISCARD
  578.         new_term.c_cc[VDISCARD] = _POSIX_VDISABLE;
  579. #endif
  580.  
  581. #ifdef VWERASE
  582.         new_term.c_cc[VWERASE] = _POSIX_VDISABLE;
  583. #endif
  584.  
  585. #ifdef VLNEXT
  586.         new_term.c_cc[VLNEXT] = _POSIX_VDISABLE;
  587. #endif
  588.  
  589.         ioctl(TTY_OUTPUT, TCSETAW, &new_term);
  590.         ospeed = new_term.c_cflag & CBAUD;
  591. #else
  592.         new_arg   = old_arg;
  593.         new_targ  = old_targ;
  594.         new_ltarg = old_ltarg;
  595.         new_arg.sg_flags = ((old_arg.sg_flags &
  596.                          ~(ECHO | CRMOD | XTABS | ALLDELAY | TILDE)) | CBREAK);
  597.         new_targ.t_intrc   = key_INTERRUPT;     /* Ctrl-G */
  598.         new_targ.t_quitc   = key_INTERRUPT;     /* Ctrl-G */
  599.         new_targ.t_eofc    = _POSIX_VDISABLE;
  600.         new_targ.t_brkc    = _POSIX_VDISABLE;
  601.         new_ltarg.t_lnextc = _POSIX_VDISABLE;
  602.         new_ltarg.t_flushc = _POSIX_VDISABLE;
  603.         new_ltarg.t_werasc = _POSIX_VDISABLE;
  604.         new_ltarg.t_rprntc = _POSIX_VDISABLE;
  605.         new_ltarg.t_dsuspc = _POSIX_VDISABLE;   /* DSUSPC (delayed SUSPC,^Y) */
  606.         new_ltarg.t_suspc  = key_SUSPEND;
  607.  
  608.         ioctl(TTY_OUTPUT, TIOCSETN, &new_arg);
  609.         ioctl(TTY_OUTPUT, TIOCSETC, &new_targ);
  610.         ioctl(TTY_OUTPUT, TIOCSLTC, &new_ltarg);
  611.         ospeed = new_arg.sg_ospeed;
  612. #endif /* HAVE_SYSTEMVTTY */
  613. #endif /* HAVE_POSIXTTY */
  614.     }
  615.     else
  616. #ifdef HAVE_POSIXTTY
  617.         tcsetattr(TTY_OUTPUT, TCSADRAIN, &old_term);
  618. #else
  619. #ifdef HAVE_SYSTEMVTTY
  620.         ioctl(TTY_OUTPUT, TCSETAW, &old_term);
  621. #else
  622.         ioctl(TTY_OUTPUT, TIOCSETN, &old_arg);
  623.         ioctl(TTY_OUTPUT, TIOCSETC, &old_targ);
  624.         ioctl(TTY_OUTPUT, TIOCSLTC, &old_ltarg);
  625. #endif /* HAVE_SYSTEMVTTY */
  626. #endif /* HAVE_POSIXTTY */
  627.  
  628.     tty_mode = mode;
  629.     tty_defaults();
  630. }
  631.  
  632.  
  633. /* Set the interrupt character.  */
  634.  
  635. void
  636. tty_set_interrupt_char(c)
  637.     unsigned char c;
  638. {
  639. #ifdef HAVE_POSIXTTY
  640.     struct termios current_term;
  641.  
  642.     tcgetattr(TTY_OUTPUT, ¤t_term);
  643.     current_term.c_cc[VINTR] = c;
  644.     current_term.c_cc[VQUIT] = c;
  645.     tcsetattr(TTY_OUTPUT, TCSADRAIN, ¤t_term);
  646. #else
  647. #ifdef HAVE_SYSTEMVTTY
  648.     struct termio current_term;
  649.  
  650.     ioctl(TTY_OUTPUT, TCGETA, ¤t_term);
  651.     current_term.c_cc[VINTR] = c;
  652.     current_term.c_cc[VQUIT] = c;
  653.     ioctl(TTY_OUTPUT, TCSETAW, ¤t_term);
  654. #else
  655.     struct tchars current_targ;
  656.  
  657.     ioctl(TTY_OUTPUT, TIOCGETC, ¤t_targ);
  658.     current_targ.t_intrc = c;
  659.     current_targ.t_quitc = c;
  660.     ioctl(TTY_OUTPUT, TIOCSETC, ¤t_targ);
  661. #endif /* HAVE_SYSTEMVTTY */
  662. #endif /* HAVE_POSIXTTY */
  663. }
  664.  
  665.  
  666. /* This function is called to restore the canonic mode at exit.  */
  667.  
  668. void
  669. tty_exit()
  670. {
  671.     if (tty_mode == TTY_NONCANONIC)
  672.     {
  673.         tty_set_mode(TTY_CANONIC);
  674.         tty_clear();
  675.     }
  676.     else
  677.         tty_defaults();
  678. }
  679.  
  680.  
  681. /* Converts a key sequence from the human readable, '^' based form into a
  682.    computer usable form.  */
  683.  
  684. char *
  685. tty_key_convert(key_seq)
  686.     unsigned char *key_seq;
  687. {
  688.     unsigned char *first;
  689.     unsigned char *second;
  690.  
  691.  
  692.     first = second = key_seq;
  693.  
  694.     if (tty_kbdmode == 0 && *key_seq != '^')
  695.         return NULL;
  696.  
  697.     while (*second)
  698.     {
  699.         if (*second == '^')
  700.         {
  701.             if (*++second)
  702.                 *first++ = key_ctrl_table[(*second++ & 0x7F) - ' '];
  703.             else
  704.                 return NULL;
  705.         }
  706.         else
  707.             *first++ = *second++;
  708.     }
  709.  
  710.     *first = 0;
  711.     return (char *)key_seq;
  712. }
  713.  
  714.  
  715. /* Set the curses-like optimization level.  Returns the previous level.
  716.    See the tty_write comment for more detail.  */
  717.  
  718. int
  719. tty_set_optimization_level(level)
  720.     int level;
  721. {
  722.     int old_tty_optimization_level = tty_optimization_level;
  723.  
  724.     tty_optimization_level = level;
  725.  
  726.     return old_tty_optimization_level;
  727. }
  728.  
  729.  
  730. /* Used by tputs() to output characters. Actually we are only storing them in
  731.    a buffer (tty_buf[]) flushing them later with tty_flush().  */
  732.  
  733. int
  734. tty_out_char(c)
  735.     int c;
  736. {
  737.     return tty_buf[tty_index++] = (char)c;
  738. }
  739.  
  740.  
  741. /* Flush the tty_buf buffer.  */
  742.  
  743. void
  744. tty_flush()
  745. {
  746.     xwrite(TTY_OUTPUT, tty_buf, tty_index);
  747.     tty_index = 0;
  748. }
  749.  
  750.  
  751. /* Clear the screen using the current color attributes.  */
  752.  
  753. void
  754. tty_clear()
  755. {
  756.     memset(tty_screen, ' ', rows * columns * sizeof(unsigned char));
  757.     memset(tty_attributes, tty_current_attribute,
  758.            rows * columns * sizeof(unsigned char));
  759.     tputs(TTY_CLEAR_SCREEN, rows, tty_out_char);
  760.     tty_flush();
  761. }
  762.  
  763.  
  764. /* Touch the tty, getting rid of any possible optimization.  */
  765.  
  766. void
  767. tty_touch()
  768. {
  769.     memset(tty_screen, 0, rows * columns * sizeof(unsigned char));
  770. }
  771.  
  772.  
  773. /* Move the cursor.  */
  774.  
  775. void
  776. tty_cursormove(y, x)
  777.     int y, x;
  778. {
  779.     char *str;
  780.  
  781.     str = tgoto(TTY_CURSOR_MOVE, x, y);
  782.     tputs(str, 1, tty_out_char);
  783.     tty_flush();
  784.  
  785.     tty_cursor_x = x;
  786.     tty_cursor_y = y;
  787. }
  788.  
  789.  
  790. /* Notify the cursor change. Used in the output optimization code.  */
  791.  
  792. void
  793. tty_cursormove_notify(y, x)
  794.     int y, x;
  795. {
  796.     tty_cursormove_notified = 1;
  797.     tty_cursor_x = x;
  798.     tty_cursor_y = y;
  799. }
  800.  
  801.  
  802. /* Setup the reverse video status. This is only used internally by the code in
  803.    this file so it is declared 'static'.  */
  804.  
  805. static void
  806. tty_reverse(status)
  807.     int status;
  808. {
  809.     if (status == ON)
  810.     {
  811.         if (TTY_REVERSE_ON)
  812.         {
  813.             tputs(TTY_REVERSE_ON, 1, tty_out_char);
  814.             tty_flush();
  815.         }
  816.     }
  817.     else
  818.     {
  819.         if (TTY_ATTRIBUTES_OFF)
  820.         {
  821.             tputs(TTY_ATTRIBUTES_OFF, 1, tty_out_char);
  822.             tty_flush();
  823.         }
  824.         rv_status = OFF;
  825.         /* same comment as in tty_brightness() */
  826.         if (br_status == ON) tty_brightness(ON);
  827.     }
  828.  
  829.     rv_status = status;
  830. }
  831.  
  832.  
  833. /* Setup the foreground color. Use the ANSI color sequence where possible or
  834.    tty_reverse() for monochrome terminals.  */
  835.  
  836. void
  837. tty_foreground(color)
  838.     int color;
  839. {
  840.     char str[16];
  841.  
  842.     memcpy(str, ansi_foreground, sizeof(ansi_foreground));
  843.  
  844.     if (AnsiColorSequences == ON)
  845.     {
  846.         str[3] += (fg_color = color);
  847.         xwrite(TTY_OUTPUT, str, sizeof(ansi_foreground));
  848.     }
  849.     else
  850.         tty_reverse((fg_color = color) != WHITE);
  851.  
  852.     tty_current_attribute = (tty_current_attribute & 0xF8) | fg_color;
  853. }
  854.  
  855.  
  856. /* Setup the background color. Use the ANSI color sequence where possible or
  857.    tty_reverse() for monochrome terminals.  */
  858.  
  859. void
  860. tty_background(color)
  861.     int color;
  862. {
  863.     char str[16];
  864.  
  865.     memcpy(str, ansi_background, sizeof(ansi_background));
  866.  
  867.     if (AnsiColorSequences == ON)
  868.     {
  869.         str[3] += (bg_color = color);
  870.         xwrite(TTY_OUTPUT, str, sizeof(ansi_background));
  871.     }
  872.     else
  873.         tty_reverse((bg_color = color) != BLACK);
  874.  
  875.     tty_current_attribute = (tty_current_attribute & 0xC7) | (bg_color << 3);
  876. }
  877.  
  878.  
  879. /* Setup the brightness status. See the comment below.  */
  880.  
  881. void
  882. tty_brightness(status)
  883.     int status;
  884. {
  885.     if (status == ON)
  886.     {
  887.         if (TTY_BRIGHT_ON)
  888.         {
  889.             tputs(TTY_BRIGHT_ON, 1, tty_out_char);
  890.             tty_flush();
  891.         }
  892.     }
  893.     else
  894.     {
  895.         if (TTY_ATTRIBUTES_OFF)
  896.         {
  897.             tputs(TTY_ATTRIBUTES_OFF, 1, tty_out_char);
  898.             tty_flush();
  899.         }
  900.  
  901.         br_status = OFF;
  902.         /* There is no terminal capability for brightness off (or bold off).
  903.            We are using the 'me' capability (where available) which turns
  904.            off all attributes so we must restore the reverse status after
  905.            that.  There is no need to restore the foreground & background
  906.            colors because we've always put tty_brightness(status) *BEFORE*
  907.            tty_foreground(color) or tty_background(color).  */
  908.         if (rv_status == ON)
  909.             tty_reverse(ON);
  910.     }
  911.  
  912.     br_status = status;
  913.  
  914.     tty_current_attribute = (tty_current_attribute & 0xBF) | (br_status << 6);
  915. }
  916.  
  917.  
  918. /* Set the brightness, foreground and background together.  */
  919.  
  920. void
  921. tty_colors(brightness, foreground, background)
  922.     int brightness, foreground, background;
  923. {
  924.     tty_brightness(brightness);
  925.     tty_foreground(foreground);
  926.     tty_background(background);
  927. }
  928.  
  929.  
  930. /* Pavarotti is better, but we are doing our best...  */
  931.  
  932. void
  933. tty_beep()
  934. {
  935.     char c = 7;
  936.  
  937.     xwrite(TTY_OUTPUT, &c, 1);
  938. }
  939.  
  940.  
  941. /* Setup the cursor status (where possible). Make it invisible during screen
  942.    refreshes and restore it afterward.  */
  943.  
  944. void
  945. tty_cursor(status)
  946.     int status;
  947. {
  948.     if ((cursor_status = status))
  949.     {
  950.         if (TTY_CURSOR_ON)
  951.         {
  952.             tputs(TTY_CURSOR_ON, 1, tty_out_char);
  953.             tty_flush();
  954.         }
  955.     }
  956.     else
  957.     {
  958.         if (TTY_CURSOR_OFF)
  959.         {
  960.             tputs(TTY_CURSOR_OFF, 1, tty_out_char);
  961.             tty_flush();
  962.         }
  963.     }
  964. }
  965.  
  966.  
  967. /* Store the soft terminal status in a tty_status_t structure.  */
  968.  
  969. void
  970. tty_save(status)
  971.     tty_status_t *status;
  972. {
  973.     status->fg_color      = fg_color;
  974.     status->bg_color      = bg_color;
  975.     status->br_status     = br_status;
  976.     status->rv_status     = rv_status;
  977.     status->cursor_status = cursor_status;
  978.     status->attribute     = tty_current_attribute;
  979. }
  980.  
  981.  
  982. /* Restore the soft terminal status from a tty_status_t structure.  */
  983.  
  984. void
  985. tty_restore(status)
  986.     tty_status_t *status;
  987. {
  988.     tty_colors(status->br_status, status->fg_color, status->bg_color);
  989.     tty_reverse(status->rv_status);
  990.     tty_cursor(status->cursor_status);
  991.     tty_current_attribute = status->attribute;
  992. }
  993.  
  994.  
  995. /* Restore the terminal to its default state. Use Linux specific sequences
  996.    on Linux consoles.  */
  997.  
  998. void
  999. tty_defaults()
  1000. {
  1001. #ifdef HAVE_LINUX
  1002.     if (LinuxConsole == ON)
  1003.         xwrite(TTY_OUTPUT, lc_defaults, sizeof(lc_defaults));
  1004.     else
  1005. #endif  /* HAVE_LINUX */
  1006.         if (TTY_ATTRIBUTES_OFF)
  1007.         {
  1008.             tputs(TTY_ATTRIBUTES_OFF, 1, tty_out_char);
  1009.             tty_flush();
  1010.         }
  1011.  
  1012.     tty_foreground(ForegroundAtExit);
  1013.     tty_background(BackgroundAtExit);
  1014.     br_status = rv_status = OFF;
  1015.  
  1016.     tty_cursor(ON);
  1017.     
  1018.     tty_current_attribute = (br_status << 6) | (bg_color << 3) | fg_color;
  1019. }
  1020.  
  1021.  
  1022. /* Write data to the terminal, performing optimizations according to the
  1023.    optimization level (tty_optimization_level). Actually there are two
  1024.    optimization methods:
  1025.         - (tty_optimization_level == 0)
  1026.           If the string we want to write on the screen is already there,
  1027.           don't perform the write() system call, but even if one character
  1028.           or attribute is different that the one on the screen, write the
  1029.           entire string.  This method is suitable for panel entries because
  1030.           these entries are usually completely different so the first
  1031.           difference found leads us to the conclusion that we have to update
  1032.           the entire area.
  1033.         - (tty_optimization_level == 1)
  1034.           All the characters and attributes are checked.  Only those characters
  1035.           that cannot be found on the screen are updated.  Suitable for
  1036.           updating the command line.  */
  1037.  
  1038. size_t
  1039. tty_write(buf, length)
  1040.     char *buf;
  1041.     size_t length;
  1042. {
  1043.     size_t bytes;
  1044.     int i, j = 0, x = tty_cursor_x;
  1045.     int tty_offset = (tty_cursor_y * columns) + tty_cursor_x;
  1046.     unsigned char *tty_sptr = tty_screen     + tty_offset;
  1047.     unsigned char *tty_aptr = tty_attributes + tty_offset;
  1048.  
  1049.  
  1050.     if (tty_optimization_level == 1)
  1051.     {
  1052.         while (1)
  1053.         {
  1054.             for (i = j; i < length; i++)
  1055.                 if (tty_sptr[i] != (unsigned char)(buf[i]) ||
  1056.                     tty_aptr[i] != tty_current_attribute)
  1057.                     break;
  1058.  
  1059.             for (j = i; j < length; j++)
  1060.                 if (tty_sptr[j] == (unsigned char)(buf[j]) &&
  1061.                     tty_aptr[j] == tty_current_attribute)
  1062.                     break;
  1063.  
  1064.             bytes = j - i;
  1065.  
  1066.             if (bytes != 0)
  1067.             {
  1068.                 memcpy(tty_sptr + i, buf + i, bytes);
  1069.                 memset(tty_aptr + i, tty_current_attribute, bytes);
  1070.                 tty_cursormove(tty_cursor_y, x + i);
  1071.                 xwrite(TTY_OUTPUT, (char *)tty_sptr + i, bytes);
  1072.             }
  1073.             else
  1074.             {
  1075.                 tty_cursormove_notified = 0;
  1076.                 tty_cursor_x = x + length;
  1077.                 return length;
  1078.             }
  1079.         }
  1080.     }
  1081.  
  1082.     if (memcmp(tty_sptr, buf, length) == 0)
  1083.     {
  1084.         for (i = 0; i < length; i++)
  1085.             if (tty_aptr[i] != tty_current_attribute)
  1086.             {
  1087.                 buf    += i;
  1088.                 length -= i;
  1089.         tty_cursor_x += i;
  1090.         tty_cursormove_notified = 1;
  1091.                 goto write_needed;
  1092.             }
  1093.  
  1094.         tty_cursor_x += length;
  1095.     tty_cursormove_notified = 1;
  1096.         return length;
  1097.     }
  1098.  
  1099.   write_needed:
  1100.  
  1101.     memcpy(tty_sptr, buf, length);
  1102.     memset(tty_aptr, tty_current_attribute, length);
  1103.  
  1104.     if (tty_cursormove_notified)
  1105.         tty_cursormove(tty_cursor_y, tty_cursor_x);
  1106.  
  1107.     tty_cursor_x += length;
  1108.     tty_cursormove_notified = 0;
  1109.     return xwrite(TTY_OUTPUT, buf, length);
  1110. }
  1111.  
  1112.  
  1113. /* Read data from terminal.  */
  1114.  
  1115. size_t
  1116. tty_read(buf, length)
  1117.     char *buf;
  1118.     size_t length;
  1119. {
  1120.     size_t bytes;
  1121.  
  1122.     if (tty_enter_idle_hook)
  1123.         (*tty_enter_idle_hook)();
  1124.  
  1125.     bytes = xread(TTY_INPUT, buf, length);
  1126.  
  1127.     if (tty_exit_idle_hook)
  1128.         (*tty_exit_idle_hook)();
  1129.  
  1130.     return bytes;
  1131. }
  1132.  
  1133.  
  1134. /* Get a character from the terminal. For better performance on high loaded
  1135.    systems, read as many data as available.  */
  1136.  
  1137. int
  1138. tty_get_char()
  1139. {
  1140.     if (keyno)
  1141.         return keybuf[keyno--, keyindex++];
  1142.  
  1143.     /* No interrupt/quit character.  */
  1144.     tty_set_interrupt_char(-1);
  1145.  
  1146.     for (keyindex = 0; (keyno = tty_read(keybuf, 1024)) < 0;);
  1147.  
  1148.     /* Restore ^G as the interrupt/quit character.  */
  1149.     tty_set_interrupt_char(key_INTERRUPT);
  1150.  
  1151.     return keyno ? keybuf[keyno--, keyindex++] : -1;
  1152. }
  1153.  
  1154.  
  1155. /* Write a character to the screen.  */
  1156.  
  1157. size_t
  1158. tty_put_char(c)
  1159.     char c;
  1160. {
  1161.     return tty_write(&c, 1);
  1162. }
  1163.  
  1164.  
  1165. /* Insert a key sequence into the list.  */
  1166.  
  1167. void
  1168. tty_key_list_insert_sequence(key, key_seq, aux_data)
  1169.     tty_key_t **key;
  1170.     unsigned char *key_seq;
  1171.     void *aux_data;
  1172. {
  1173.     tty_key_t *new_key;
  1174.  
  1175.     new_key = (tty_key_t *)xmalloc(sizeof(tty_key_t));
  1176.     new_key->key_seq = (unsigned char *)xstrdup(key_seq);
  1177.     new_key->aux_data = aux_data;
  1178.     new_key->next = *key;
  1179.     *key = new_key;
  1180. }
  1181.  
  1182.  
  1183. /* Parse the key list, inserting the new key sequence in the proper
  1184.    position.  */
  1185.  
  1186. void
  1187. tty_key_list_insert(key_seq, aux_data)
  1188.     unsigned char *key_seq;
  1189.     void *aux_data;
  1190. {
  1191.     static tty_key_t **key = NULL;
  1192.  
  1193.     if (*key_seq == 0)
  1194.         return;               /* bad key sequence !  */
  1195.  
  1196.     /* Try to optimize by checking if the current entry should be added
  1197.        after the current position.  Avoid re-parsing the entire list if
  1198.        so.  */
  1199.     if (key == NULL || strcmp((char *)key_seq, (*key)->key_seq) <= 0)
  1200.         key = &key_list_head;
  1201.  
  1202.     for (; *key; key = &(*key)->next)
  1203.         if (strcmp((char *)key_seq, (*key)->key_seq) <= 0)
  1204.         {
  1205.             tty_key_list_insert_sequence(key, key_seq, aux_data);
  1206.             return;
  1207.         }
  1208.  
  1209.     tty_key_list_insert_sequence(key, key_seq, aux_data);
  1210. }
  1211.  
  1212.  
  1213. /* Incremental searches a key in the list. Returns a pointer to the first
  1214.    sequence that matches.  */
  1215.  
  1216. tty_key_t *
  1217. tty_key_search(key_seq)
  1218.     char *key_seq;
  1219. {
  1220.     int cmp;
  1221.  
  1222.     if (current_key == NULL)
  1223.         return NULL;
  1224.  
  1225.     for (; current_key; current_key = current_key->next)
  1226.     {
  1227.         cmp = strcmp(key_seq, (char *)current_key->key_seq);
  1228.  
  1229.         if (cmp == 0)
  1230.             return current_key;
  1231.  
  1232.         if (cmp  < 0)
  1233.             break;
  1234.     }
  1235.  
  1236.     if (current_key == NULL ||
  1237.         strncmp(key_seq, (char *)current_key->key_seq, strlen(key_seq)))
  1238.         return (tty_key_t *)-1;
  1239.     else
  1240.         return NULL;
  1241. }
  1242.  
  1243.  
  1244. /* Force the next key search to start from the begining of the list.  */
  1245.  
  1246. void
  1247. tty_key_search_restart()
  1248. {
  1249.     current_key = key_list_head;
  1250. }
  1251.  
  1252.  
  1253. #if 0
  1254. /* Delete a key from the list. Don't remove this function, God only knows
  1255.    when I'll gonna need it...  */
  1256.  
  1257. void
  1258. tty_key_list_delete()
  1259. {
  1260.     tty_key_t *key, *next_key;
  1261.  
  1262.     for (key = key_list_head; key; key = next_key)
  1263.     {
  1264.         next_key = key->next;
  1265.         xfree(key->key_seq);
  1266.         xfree(key);
  1267.     }
  1268. }
  1269. #endif
  1270.  
  1271.  
  1272. /* Get the first key available, returning also the repeat count, that is,
  1273.    the number of times the key has been pressed. These feature is  mainly
  1274.    used by the calling routines to perform optimizations. For example, if
  1275.    you press the down arrow several times, the caller  can  display  only
  1276.    the final position, saving a lot of time. If you have ever worked with
  1277.    this program on high loaded systems, I'm sure you know what I mean.  */
  1278.  
  1279. tty_key_t *
  1280. tty_get_key(repeat_count)
  1281.     int *repeat_count;
  1282. {
  1283.     int i, c;
  1284.     tty_key_t *key;
  1285.     unsigned char key_seq[64];
  1286.  
  1287.  
  1288.   restart:
  1289.  
  1290.     while ((c = tty_get_char()) == -1);
  1291.  
  1292.     if (repeat_count)
  1293.         *repeat_count = 1;
  1294.  
  1295.     /* Handle ^SPC.  */ 
  1296.     if (c == 0)
  1297.         c = 0xff;
  1298.  
  1299.     if (!tty_kbdmode)
  1300.     {
  1301.         if (c == '\n' || c == '\r')
  1302.             c = key_ENTER;
  1303.  
  1304.         if (is_print(c) || c == key_INTERRUPT)
  1305.         {
  1306.             default_key.key_seq[0] = c;
  1307.             default_key.key_seq[1] = 0;
  1308.             return &default_key;
  1309.         }
  1310.     }
  1311.  
  1312.     tty_key_search_restart();
  1313.  
  1314.     for (i = 0; i < MAX_KEY_LENGTH; i++)
  1315.     {
  1316.         /* Handle brain-damaged key sequences correctly.  If  a  0  is
  1317.            found, transform it in a 0xff.  I don't know how smart this
  1318.            is, but right know I don't feel like doing it otherwise.  */
  1319.         if (c == 0)
  1320.             c = 0xff;
  1321.  
  1322.         key_seq[i    ] = c;
  1323.         key_seq[i + 1] = 0;
  1324.  
  1325.         key = tty_key_search(key_seq);
  1326.  
  1327.         if (key == (tty_key_t *)-1)
  1328.             goto restart;
  1329.  
  1330.         if (key)
  1331.             break;
  1332.  
  1333.         while ((c = tty_get_char()) == -1);
  1334.     }
  1335.  
  1336.     if (i == MAX_KEY_LENGTH)
  1337.     goto restart;
  1338.  
  1339.     if (repeat_count)
  1340.         while (keyno > i && (memcmp(key_seq, &keybuf[keyindex], i + 1) == 0))
  1341.         {
  1342.             keyindex += i + 1;
  1343.             keyno    -= i + 1;
  1344.             (*repeat_count)++;
  1345.         }
  1346.  
  1347.     return key;
  1348. }
  1349.  
  1350.  
  1351. /* Retreive the screen size. Try ioctl(TIOCGWINSZ, ...) and, if it fails
  1352.    or it is not supported, use the environment variables LINES & COLUMNS
  1353.    (if possible). If both methods fail, use the default 80x24.  */
  1354.  
  1355. void
  1356. tty_get_size(_columns, _rows)
  1357.     int *_columns, *_rows;
  1358. {
  1359.     char *env;
  1360.  
  1361. #ifdef HAVE_WINSZ
  1362.     struct winsize winsz;
  1363. #endif /* HAVE_WINSZ */
  1364.  
  1365.     int temp_rows, temp_columns;
  1366.  
  1367.     columns = rows = temp_columns = temp_rows = 0;
  1368.  
  1369. #ifdef HAVE_WINSZ
  1370.  
  1371. #if defined TIOCGSIZE && !defined TIOCGWINSZ
  1372. #define TIOCGWINSZ TIOCGSIZE
  1373. #endif
  1374.  
  1375.     ioctl(TTY_OUTPUT, TIOCGWINSZ, &winsz);
  1376.  
  1377.     if (winsz.ws_col && winsz.ws_row)
  1378.     {
  1379.         temp_columns = winsz.ws_col;
  1380.         temp_rows    = winsz.ws_row;
  1381.     }
  1382. #endif /* HAVE_WINSZ */
  1383.  
  1384.     if ((env = getenv("COLUMNS"))) sscanf(env, "%d", &columns);
  1385.     if ((env = getenv("LINES"  ))) sscanf(env, "%d", &rows);
  1386.  
  1387. #ifdef HAVE_WINSZ
  1388.     if (columns < 80) columns = temp_columns;
  1389.     if (rows    < 10) rows    = temp_rows;
  1390. #endif /* HAVE_WINSZ */
  1391.  
  1392.     if (columns < 80 || columns > MAX_TTY_COLUMNS) columns = 80;
  1393.     if (rows    < 10 || rows    > MAX_TTY_ROWS)    rows    = 24;
  1394.  
  1395.     *_columns = columns;
  1396.     *_rows    = rows;
  1397. }
  1398.  
  1399.  
  1400. /* Dump the screen. Only used in Linux if the terminal is a virtual
  1401.    console.  */
  1402.  
  1403. void
  1404. tty_get_screen(buf)
  1405.     char *buf;
  1406. {
  1407. #ifdef HAVE_LINUX
  1408.     if (LinuxConsole == ON)
  1409.     {
  1410.         int vcs, bytes_read;
  1411.         char vcsname[16] = "/dev/vcsaX";
  1412.  
  1413.         vcsname[9] = tty_name[tty_name_len - 1]; 
  1414.         vcs = open(vcsname, O_RDONLY);
  1415.         bytes_read = read(vcs, buf, 4 + rows * columns * 2);
  1416.         close(vcs);
  1417.  
  1418.         vcs_read_ok = (bytes_read != -1);
  1419.     }
  1420. #endif  /* HAVE_LINUX */
  1421. }
  1422.  
  1423.  
  1424. /* Restore the screen. If the terminal is not a Linux virtual console, just
  1425.    restore it to the default state.  */
  1426.  
  1427. void
  1428. tty_put_screen(buf)
  1429.     char *buf;
  1430. {    
  1431.     tty_defaults();
  1432.     tty_cursormove(0, 0);
  1433.  
  1434. #ifdef HAVE_LINUX
  1435.     if (LinuxConsole == ON)
  1436.     {
  1437.         if (vcs_read_ok)
  1438.         {
  1439.             int vcs, bytes_written;
  1440.             char vcsname[16] = "/dev/vcsaX";
  1441.           
  1442.             tty_touch();
  1443.             vcsname[9] = tty_name[tty_name_len - 1]; 
  1444.             vcs = open(vcsname, O_WRONLY);
  1445.             bytes_written = write(vcs, buf, 4 + rows * columns * 2);
  1446.             close(vcs);
  1447.  
  1448.             /* We might have the permission to read the contents of the
  1449.                virtual console, but not the permission to read it.  */
  1450.             if (bytes_written != -1)
  1451.                 tty_cursormove(buf[3], buf[2]);
  1452.             else
  1453.             {
  1454.                 tty_defaults();
  1455.                 tty_clear();
  1456.             }
  1457.         }
  1458.         else
  1459.         {
  1460.             tty_defaults();
  1461.             tty_clear();
  1462.         }
  1463.     }
  1464.     else
  1465.     {
  1466.         tty_defaults();
  1467.         tty_clear();
  1468.     }
  1469. #else   /* !HAVE_LINUX */
  1470.     tty_defaults();
  1471.     tty_clear();
  1472. #endif  /* !HAVE_LINUX */
  1473. }
  1474.  
  1475.  
  1476. /* Get the color index from the colors[] index table.  */ 
  1477.  
  1478. int
  1479. tty_get_color_index(colorname)
  1480.     char *colorname;
  1481. {
  1482.     int i;
  1483.  
  1484.     for (i = 0; i < 10; i++)
  1485.         if (strcmp(colors[i], colorname) == 0)
  1486.             return (i < 8) ? i : (i - 8);
  1487.     return -1;
  1488. }
  1489.  
  1490.  
  1491. /* Return the capability of a given termcap symbol. */
  1492.  
  1493. char *
  1494. tty_get_symbol_key_seq(symbol)
  1495.     char *symbol;
  1496. {
  1497.     int i;
  1498.  
  1499.     for (i = TTY_FIRST_SYMBOL_KEY; i < TTY_USED_CAPABILITIES; i++)
  1500.         if (strcmp(tty_capability[i].symbol, symbol) == 0)
  1501.             return tty_capability[i].capability;
  1502.  
  1503.     return NULL;
  1504. }
  1505.  
  1506.  
  1507. void
  1508. tty_get_exit_colors()
  1509. {
  1510.     use_section("[Setup]");
  1511.  
  1512.     /* Try to read the foreground and background colors that we should restore
  1513.        at exit. The default are white/black. */
  1514.     ForegroundAtExit = get_const_var("ForegroundAtExit", colors, 8, 7);
  1515.     BackgroundAtExit = get_const_var("BackgroundAtExit", colors, 8, 0);
  1516. }
  1517.  
  1518. /* Get the entire set of requiresd termcap/terminfo capabilities. It performs
  1519.    consistency checkings trying to recover as well as possible. */
  1520.  
  1521. void
  1522. tty_get_capabilities()
  1523. {
  1524. #ifdef HAVE_LINUX
  1525.     struct stat statbuf;
  1526. #endif /* HAVE_LINUX */
  1527.     char *capability_buf, *tmp;
  1528.     int err, i, term_errors = 0;
  1529.     char *termtype = getenv("TERM");
  1530.  
  1531. #ifdef HAVE_LINUX
  1532.     fstat(TTY_OUTPUT, &statbuf);
  1533.     if ((statbuf.st_rdev >> 8) == LINUX_VC_MAJOR &&
  1534.         ((unsigned)(statbuf.st_rdev & 0xFF)) <= 8)
  1535.         LinuxConsole = ON;
  1536.     else
  1537.         LinuxConsole = OFF;
  1538. #endif /* HAVE_LINUX */
  1539.  
  1540.     if (termtype == NULL)
  1541.     {
  1542.         fprintf(stderr, "%s: can't find the TERM environment variable, ",
  1543.                 program);
  1544.         goto switch_to_vt100;
  1545.     }
  1546.  
  1547.     if (strlen(termtype) > 63)
  1548.     {
  1549.         fprintf(stderr, "%s: the TERM environment variable is too long, ",
  1550.                 program);
  1551.       switch_to_vt100:
  1552.         fprintf(stderr, "trying vt100 ...\n");
  1553.         termtype = vt100;
  1554.     }
  1555.  
  1556.     err = tgetent(term_buf, termtype);
  1557.  
  1558.     if (err == -1)
  1559.     {
  1560.         fprintf(stderr, "%s: can't find the %s database.\n",
  1561.                 program, term_database);
  1562.         fprintf(stderr, "%s: check your %s environment variable ...\n",
  1563.                 program, term_env);
  1564.         exit(1);
  1565.     }
  1566.  
  1567.     if (err == 0)
  1568.     {
  1569.         fprintf(stderr,
  1570.                 "%s: can't find the terminal type %s in the %s database.\n",
  1571.                 program, termtype, term_database);
  1572.         exit(1);
  1573.     }
  1574.     tty_type = xstrdup(termtype);
  1575.  
  1576.     capability_buf = xmalloc(2048);
  1577.  
  1578.     tmp = tgetstr(TTY_PAD_CHAR_NAME, &capability_buf);
  1579.     PC = tmp ? *tmp : 0;
  1580.  
  1581.     BC = tgetstr(TTY_LEFT_ONE_SPACE_NAME, &capability_buf);
  1582.     UP = tgetstr(TTY_UP_ONE_LINE_NAME,    &capability_buf);
  1583.  
  1584.     if (BC == NULL || UP == NULL)
  1585.         BC = UP = NULL;
  1586.  
  1587.     TTY_ATTRIBUTES_OFF = tgetstr(TTY_ATTRIBUTES_OFF_NAME, &capability_buf);
  1588.     TTY_REVERSE_ON     = tgetstr(TTY_REVERSE_ON_NAME,     &capability_buf);
  1589.     TTY_BRIGHT_ON      = tgetstr(TTY_BRIGHT_ON_NAME,      &capability_buf);
  1590.  
  1591.     if (TTY_ATTRIBUTES_OFF == NULL)
  1592.     {
  1593. #ifdef HAVE_LINUX
  1594.         if (LinuxConsole)
  1595.             TTY_ATTRIBUTES_OFF = lc_attr_off;   /* I *really* hate this ! */
  1596.         else
  1597. #endif /* HAVE_LINUX */
  1598.             TTY_REVERSE_ON = TTY_BRIGHT_ON = NULL;
  1599.     }
  1600.  
  1601.  
  1602.     /* I have problems using (and understanding) hpterm, so I've used a
  1603.        small hack to get it work. I hope I will be able to change this
  1604.        someday...  */
  1605.  
  1606.     if (strcmp(termtype, "hpterm") == 0)
  1607.         TTY_ATTRIBUTES_OFF = TTY_REVERSE_ON = TTY_BRIGHT_ON = NULL;
  1608.  
  1609.     TTY_CURSOR_OFF = tgetstr(TTY_CURSOR_OFF_NAME, &capability_buf);
  1610.     TTY_CURSOR_ON  = tgetstr(TTY_CURSOR_ON_NAME,  &capability_buf);
  1611.  
  1612.     if (TTY_CURSOR_OFF == NULL || TTY_CURSOR_ON == NULL)
  1613.         TTY_CURSOR_ON = TTY_CURSOR_OFF = NULL;
  1614.  
  1615.     TTY_CLEAR_SCREEN = tgetstr(TTY_CLEAR_SCREEN_NAME, &capability_buf);
  1616.     TTY_CURSOR_MOVE  = tgetstr(TTY_CURSOR_MOVE_NAME,  &capability_buf);
  1617.  
  1618.     for (i = TTY_FIRST_SYMBOL_KEY; i < TTY_USED_CAPABILITIES; i++)
  1619.         tty_capability[i].capability = tgetstr(tty_capability[i].name,
  1620.                                                &capability_buf);
  1621.  
  1622.     for (i = 0; i < TTY_USED_CAPABILITIES; i++)
  1623.         if (tty_capability[i].capability == NULL)
  1624.             if (tty_capability[i].indispensable)
  1625.             {
  1626.                 term_errors++;
  1627.                 fprintf(stderr,
  1628.                         "%s: can't find the '%s' terminal capability.\n",
  1629.                         program, tty_capability[i].name);
  1630.             }
  1631.  
  1632.     if (term_errors)
  1633.     {
  1634.         fprintf(stderr, "%s: %d errors. Your terminal is too dumb :-< .\n",
  1635.                 program, term_errors);
  1636.         exit(1);
  1637.     }
  1638. }
  1639.